﻿using System;
using GeoAPI.Geometries;
using YJKGridTopologyCal.Algorithm;

namespace YJKGridTopologyCal.Triangulate.QuadEdge
{
	public class Vertex : IEquatable<Vertex>
	{
		public Vertex(double x, double y)
		{
			this._p = new Coordinate(x, y);
		}

		public Vertex(double x, double y, double z)
		{
			this._p = new Coordinate(x, y, z);
		}

		public Vertex(Coordinate p)
		{
			this._p = new Coordinate(p);
		}

		public double X
		{
			get
			{
				return this._p.X;
			}
		}

		public double Y
		{
			get
			{
				return this._p.Y;
			}
		}

		public double Z
		{
			get
			{
				return this._p.Z;
			}
			set
			{
				this._p.Z = value;
			}
		}

		public Coordinate Coordinate
		{
			get
			{
				return this._p;
			}
		}

		public override string ToString()
		{
			return string.Concat(new object[]
			{
				"POINT (",
				this._p.X,
				" ",
				this._p.Y,
				")"
			});
		}

		public bool Equals(Vertex x)
		{
			return this._p.X == x.X && this._p.Y == x.Y;
		}

		public bool Equals(Vertex x, double tolerance)
		{
			return this._p.Distance(x.Coordinate) < tolerance;
		}

		public int Classify(Vertex p0, Vertex p1)
		{
			Vertex vertex = p1.Sub(p0);
			Vertex vertex2 = this.Sub(p0);
			double num = vertex.CrossProduct(vertex2);
			if (num > 0.0)
			{
				return 0;
			}
			if (num < 0.0)
			{
				return 1;
			}
			if (vertex.X * vertex2.X < 0.0 || vertex.Y * vertex2.Y < 0.0)
			{
				return 3;
			}
			if (vertex.Magnitude() < vertex2.Magnitude())
			{
				return 2;
			}
			if (p0.Equals(this))
			{
				return 5;
			}
			if (p1.Equals(this))
			{
				return 6;
			}
			return 4;
		}

		private double CrossProduct(Vertex v)
		{
			return this._p.X * v.Y - this._p.Y * v.X;
		}

		private double Dot(Vertex v)
		{
			return this._p.X * v.X + this._p.Y * v.Y;
		}

		private Vertex Times(double c)
		{
			return new Vertex(c * this._p.X, c * this._p.Y);
		}

		private Vertex Sum(Vertex v)
		{
			return new Vertex(this._p.X + v.X, this._p.Y + v.Y);
		}

		private Vertex Sub(Vertex v)
		{
			return new Vertex(this._p.X - v.X, this._p.Y - v.Y);
		}

		private double Magnitude()
		{
			return Math.Sqrt(this._p.X * this._p.X + this._p.Y * this._p.Y);
		}

		private Vertex Cross()
		{
			return new Vertex(this._p.Y, -this._p.X);
		}

		public bool IsInCircle(Vertex a, Vertex b, Vertex c)
		{
			return TrianglePredicate.IsInCircleRobust(a._p, b._p, c._p, this._p);
		}

		private bool IsCcw(Vertex b, Vertex c)
		{
			return (b._p.X - this._p.X) * (c._p.Y - this._p.Y) - (b._p.Y - this._p.Y) * (c._p.X - this._p.X) > 0.0;
		}

		internal bool RightOf(QuadEdge e)
		{
			return this.IsCcw(e.Dest, e.Orig);
		}

		private bool LeftOf(QuadEdge e)
		{
			return this.IsCcw(e.Orig, e.Dest);
		}

		private static HCoordinate Bisector(Vertex a, Vertex b)
		{
			double num = b.X - a.X;
			double num2 = b.Y - a.Y;
			HCoordinate p = new HCoordinate(a.X + num / 2.0, a.Y + num2 / 2.0, 1.0);
			HCoordinate p2 = new HCoordinate(a.X - num2 + num / 2.0, a.Y + num + num2 / 2.0, 1.0);
			return new HCoordinate(p, p2);
		}

		private static double Distance(Vertex v1, Vertex v2)
		{
			return Math.Sqrt(Math.Pow(v2.X - v1.X, 2.0) + Math.Pow(v2.Y - v1.Y, 2.0));
		}

		public double CircumRadiusRatio(Vertex b, Vertex c)
		{
			double num = Vertex.Distance(this.CircleCenter(b, c), b);
			double num2 = Vertex.Distance(this, b);
			double num3 = Vertex.Distance(b, c);
			if (num3 < num2)
			{
				num2 = num3;
			}
			num3 = Vertex.Distance(c, this);
			if (num3 < num2)
			{
				num2 = num3;
			}
			return num / num2;
		}

		public Vertex MidPoint(Vertex a)
		{
			double x = (this._p.X + a.X) / 2.0;
			double y = (this._p.Y + a.Y) / 2.0;
			double z = (this._p.Z + a.Z) / 2.0;
			return new Vertex(x, y, z);
		}

		public Vertex CircleCenter(Vertex b, Vertex c)
		{
			HCoordinate p = Vertex.Bisector(new Vertex(this.X, this.Y), b);
			HCoordinate p2 = Vertex.Bisector(b, c);
			HCoordinate hcoordinate = new HCoordinate(p, p2);
			Vertex result = null;
			try
			{
				result = new Vertex(hcoordinate.GetX(), hcoordinate.GetY());
			}
			catch (NotRepresentableException)
			{
			}
			return result;
		}

		public double InterpolateZValue(Vertex v0, Vertex v1, Vertex v2)
		{
			double x = v0.X;
			double y = v0.Y;
			double num = v1.X - x;
			double num2 = v2.X - x;
			double num3 = v1.Y - y;
			double num4 = v2.Y - y;
			double num5 = num * num4 - num2 * num3;
			double num6 = this.X - x;
			double num7 = this.Y - y;
			double num8 = (num4 * num6 - num2 * num7) / num5;
			double num9 = (-num3 * num6 + num * num7) / num5;
			return v0.Z + num8 * (v1.Z - v0.Z) + num9 * (v2.Z - v0.Z);
		}

		public static double InterpolateZ(Coordinate p, Coordinate v0, Coordinate v1, Coordinate v2)
		{
			double x = v0.X;
			double y = v0.Y;
			double num = v1.X - x;
			double num2 = v2.X - x;
			double num3 = v1.Y - y;
			double num4 = v2.Y - y;
			double num5 = num * num4 - num2 * num3;
			double num6 = p.X - x;
			double num7 = p.Y - y;
			double num8 = (num4 * num6 - num2 * num7) / num5;
			double num9 = (-num3 * num6 + num * num7) / num5;
			return v0.Z + num8 * (v1.Z - v0.Z) + num9 * (v2.Z - v0.Z);
		}

		public static double InterpolateZ(Coordinate p, Coordinate p0, Coordinate p1)
		{
			double num = p0.Distance(p1);
			double num2 = p.Distance(p0);
			double num3 = p1.Z - p0.Z;
			return p0.Z + num3 * (num2 / num);
		}

		private const int LEFT = 0;

		private const int RIGHT = 1;

		private const int BEYOND = 2;

		private const int BEHIND = 3;

		private const int BETWEEN = 4;

		private const int ORIGIN = 5;

		private const int DESTINATION = 6;

		private readonly Coordinate _p;
	}
}
